package com.yn.core.dao.impl;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Transactional;

import com.yn.core.dao.BaseDao;
import com.yn.xr.common.page.GenericsUtils;
import com.yn.xr.common.page.PageResult;
import com.yn.xr.common.util.StringUtils;

/**
 * 
 * @description:BaseDao实现类
 * @fileName:BaseDaoImpl.java
 * @createTime:2015年1月26日 上午11:26:29
 * @author:肖震
 * @version 1.0.0
 * 
 */
public class BaseDaoImpl<T, ID extends Serializable> extends
		HibernateDaoSupport implements BaseDao<T, ID> {

	protected Class<T> entityClass = GenericsUtils.getSuperClassGenricType(this.getClass());

	protected String entityClassName = getEntityName(this.entityClass);

	protected String keyFieldName = getKeyFieldName(this.entityClass);

	public HibernateTemplate gethibernateTeplate() {
		return super.getHibernateTemplate();
	}

	/**
	 * 获取实体的名称
	 * 
	 * @param <E>
	 * @param clazz
	 *            实体类
	 * @return
	 */
	protected static <E> String getEntityName(Class<E> clazz) {
		String entityname = clazz.getSimpleName();
		Entity entity = clazz.getAnnotation(Entity.class);
		if (entity.name() != null && !"".equals(entity.name())) {
			entityname = entity.name();
		}
		return entityname;
	}

	public List<T> findByEntity(T entiey) {
		return super.getHibernateTemplate().findByExample(entiey);
	}

	public List<T> findByProperty(String propertyName, Object value) {
		String queryString = "from " + entityClassName + " o where o."
				+ propertyName + "= ?";
		return super.getHibernateTemplate().find(queryString, value);
	}

	public void delete(Serializable... entityids) {
		for (Object id : entityids) {
			super.getHibernateTemplate().delete(findById((Serializable) id));
		}
	}

	@Override
	public T findById(Serializable entityId) {
		if (null != entityId)
			return (T) super.getHibernateTemplate().get(entityClass, entityId);
		return null;
	}

	public void delete(T entity) {
		this.getHibernateTemplate().delete(entity);
	}

	/*
	 * @see org.usc.daos.DAO#getCount()
	 */
	public int getCount() {
		String hql = "select count( " + keyFieldName + ") from "
				+ entityClassName;
		int count = Integer.parseInt(super.getHibernateTemplate().find(hql)
				.get(0).toString());
		return count;
	}

	public Serializable saveBackId(T entity) {
		return super.getHibernateTemplate().save(entity);
	}

	public void save(T entity) {
		super.getHibernateTemplate().save(entity);
	}

	/*
	 * @see org.usc.daos.DAO#update(java.lang.Object)
	 */
	public void update(T entity) {
		super.getHibernateTemplate().update(entity);
	}

	public List<T> find(String hql) {
		List<T> list = (List<T>) this.getHibernateTemplate().find(hql);
		return list;
	}

	public List<T> findPre(String hql, Object... paramValues) {
		List<T> list = (List<T>) this.getHibernateTemplate().find(hql,
				paramValues);
		return list;
	}

	@Override
	public List findForHql(String hql) {
		List list = this.getHibernateTemplate().find(hql);
		return list;
	}

	@Override
	public List findForHqlPre(String hql, Object... paramValues) {
		List list = this.getHibernateTemplate().find(hql, paramValues);
		return list;
	}

	public PageResult<T> getScrollData(final int firstindex,
			final int maxresult, final String wherejpql,
			final Object[] queryParams,
			final LinkedHashMap<String, String> orderby) {
		final PageResult<T> queryResult = new PageResult<T>();

		super.getHibernateTemplate().execute(new HibernateCallback<T>() {

			public T doInHibernate(Session session) throws HibernateException,
					SQLException {

				String hql = "from "
						+ entityClassName
						+ " o "
						+ (wherejpql == null || "".equals(wherejpql.trim()) ? ""
								: " where " + wherejpql)
						+ buildOrderby(orderby);

				Query query = session.createQuery(hql);

				setQueryParams(query, queryParams);// where
				queryResult.setTotalRecord(query.list().size());// first get
																// size

				if (firstindex != -1 && maxresult != -1)
					query.setFirstResult(firstindex).setMaxResults(maxresult);// last
																				// page

				queryResult.setResultList(query.list());

				return null;
			}

		});

		return queryResult;

	}

	public PageResult<T> getScrollData(final int firstindex,
			final int maxresult, final String wherejpql,
			final LinkedHashMap<String, String> orderby) {
		final PageResult<T> queryResult = new PageResult<T>();

		super.getHibernateTemplate().execute(new HibernateCallback<T>() {

			public T doInHibernate(Session session) throws HibernateException,
					SQLException {
				String hql = "";
				if (StringUtils.covertEmptyStringToNull(wherejpql) != null
						&& wherejpql.substring(0, 1).equals("s")) {
					hql = wherejpql;
				} else {
					hql = "from "
							+ entityClassName
							+ " o "
							+ (wherejpql == null || "".equals(wherejpql.trim()) ? ""
									: " where " + wherejpql)
							+ buildOrderby(orderby);
				}
				Query query = session.createQuery(hql);
				// setQueryParams(query, queryParams);// where
				queryResult.setTotalRecord(query.list().size());// first get
																// size

				if (firstindex != -1 && maxresult != -1)
					query.setFirstResult(firstindex).setMaxResults(maxresult);// last
																				// page

				queryResult.setResultList(query.list());

				return null;
			}

		});

		return queryResult;

	}

	@Override
	public PageResult<T> getSQLScrollData(final int firstindex,
			final int maxresult, final String sql) {
		final PageResult<T> queryResult = new PageResult<T>();

		super.getHibernateTemplate().execute(new HibernateCallback<T>() {

			public T doInHibernate(Session session) throws HibernateException,
					SQLException {

				SQLQuery query = session.createSQLQuery(sql);
				// setQueryParams(query, queryParams);// where
				queryResult.setTotalRecord(query.list().size());// first get
																// size
				if (firstindex != -1 && maxresult != -1)
					query.setFirstResult((firstindex - 1) * maxresult)
							.setMaxResults(maxresult);// last
				// page

				queryResult.setSqlResultList(query.list());

				return null;
			}

		});

		return queryResult;
	}

	@Override
	public PageResult getSQLScrollDataNoT(final int firstindex,
			final int maxresult, final String sql) {
		final PageResult queryResult = new PageResult();

		super.getHibernateTemplate().execute(new HibernateCallback() {

			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {

				SQLQuery query = session.createSQLQuery(sql);
				// setQueryParams(query, queryParams);// where
				queryResult.setTotalRecord(query.list().size());// first get
																// size
				if (firstindex != -1 && maxresult != -1)
					query.setFirstResult((firstindex - 1) * maxresult)
							.setMaxResults(maxresult);// last
				// page

				queryResult.setSqlResultList(query.list());

				return null;
			}

		});

		return queryResult;
	}

	@Override
	public List getSQLScrollData(final String sql) {
		final List queryResult = super.getHibernateTemplate().execute(
				new HibernateCallback<List>() {

					public List doInHibernate(Session session)
							throws HibernateException, SQLException {

						SQLQuery query = session.createSQLQuery(sql);

						return query.list();
					}

				});

		return queryResult;
	}

	@Override
	public List getSQLScrollData(final String sql, final Object[] params) {
		final List queryResult = super.getHibernateTemplate().execute(
				new HibernateCallback<List>() {

					public List doInHibernate(Session session)
							throws HibernateException, SQLException {

						SQLQuery query = session.createSQLQuery(sql);
						setQueryParams(query, params);

						return query.list();
					}

				});

		return queryResult;
	}

	public PageResult<T> getScrollData(int firstindex, int maxresult,
			String wherejpql, Object[] queryParams) {
		return getScrollData(firstindex, maxresult, wherejpql, queryParams,
				null);
	}

	/*
	 * @see org.usc.daos.DAO#getScrollData(int, int, java.util.LinkedHashMap)
	 */
	public PageResult<T> getScrollData(final int firstindex,
			final int maxresult, final LinkedHashMap<String, String> orderby) {
		return getScrollData(firstindex, maxresult, null, null, orderby);

	}

	/*
	 * @see org.usc.daos.DAO#getScrollData(int, int)
	 */
	public PageResult<T> getScrollData(final int firstindex, final int maxresult) {
		return getScrollData(firstindex, maxresult, null, null, null);
	}

	/*
	 * @see org.usc.daos.DAO#getScrollData()
	 */
	public PageResult<T> getScrollData() {
		return getScrollData(-1, -1, null, null, null);
	}

	/**
	 * 获取实体的主键
	 * 
	 * @param <E>
	 * @param clazz
	 *            实体类
	 * @return 主键名
	 */
	protected static <E> String getKeyFieldName(Class<E> clazz) {
		try {
			PropertyDescriptor[] propertyDescriptors = Introspector
					.getBeanInfo(clazz).getPropertyDescriptors();
			for (PropertyDescriptor propertydesc : propertyDescriptors) {
				Method method = propertydesc.getReadMethod();
				if (null != method
						&& null != method
								.getAnnotation(javax.persistence.Id.class)) {
					return propertydesc.getName();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "id";
	}

	/**
	 * 设置HQL里边的属性值
	 * 
	 * @param query
	 * @param queryParams
	 */
	protected static void setQueryParams(Query query, Object[] queryParams) {
		if (queryParams != null && queryParams.length > 0) {
			for (int i = 0; i < queryParams.length; i++) {
				query.setParameter(i, queryParams[i]);// 从0开始
			}
		}
	}

	/**
	 * 设置HQL或者sql里边的属性值
	 * 
	 * @function:
	 * @param query
	 * @param queryParams
	 *            void
	 * @exception
	 * @author:Wuwenyong
	 * @since 1.0.0
	 */
	protected static void setQueryParams(Query query, List queryParams) {
		if (null != queryParams) {
			for (int i = 0; i < queryParams.size(); i++) {
				query.setParameter(i, queryParams.get(i));
			}
		}
	}

	/**
	 * 组装order by语句
	 * 
	 * @param orderby
	 * @return
	 */
	protected static String buildOrderby(LinkedHashMap<String, String> orderby) {
		StringBuffer orderbyql = new StringBuffer("");
		if (orderby != null && orderby.size() > 0) {
			orderbyql.append(" order by ");
			for (String key : orderby.keySet()) {
				orderbyql.append("o.").append(key).append(" ")
						.append(orderby.get(key)).append(",");
			}
			orderbyql.deleteCharAt(orderbyql.length() - 1);
		}
		return orderbyql.toString();
	}

	protected static <E> String getCountField(Class<E> clazz) {
		String out = "o";
		try {
			PropertyDescriptor[] propertyDescriptors = Introspector
					.getBeanInfo(clazz).getPropertyDescriptors();
			for (PropertyDescriptor propertydesc : propertyDescriptors) {
				Method method = propertydesc.getReadMethod();
				if (method != null
						&& method.isAnnotationPresent(EmbeddedId.class)) {
					PropertyDescriptor[] ps = Introspector.getBeanInfo(
							propertydesc.getPropertyType())
							.getPropertyDescriptors();
					out = "o."
							+ propertydesc.getName()
							+ "."
							+ (!ps[1].getName().equals("class") ? ps[1]
									.getName() : ps[0].getName());
					break;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return out;
	}

	@Transactional
	public void saveOrUpdate(T entity) {
		this.getHibernateTemplate().saveOrUpdate(entity);
	}

	@Override
	public void deleteAll(Collection<T> entities) {
		this.getHibernateTemplate().deleteAll(entities);

	}

	@Override
	public void saveOrUpdateAll(Collection<T> entities) {
		this.getHibernateTemplate().saveOrUpdateAll(entities);

	}

	@Override
	public PageResult<T> getScrollData(final int firstindex,
			final int maxresult, final Object[] queryParams, final String sql) {
		final PageResult<T> queryResult = new PageResult<T>();
		super.getHibernateTemplate().execute(new HibernateCallback<T>() {

			public T doInHibernate(Session session) throws HibernateException,
					SQLException {

				SQLQuery query = session.createSQLQuery(sql);
				setQueryParams(query, queryParams);// where
				queryResult.setTotalRecord(query.list().size());// first get
																// size
				if (firstindex != -1 && maxresult != -1)
					query.setFirstResult((firstindex - 1) * maxresult)
							.setMaxResults(maxresult);// last

				queryResult.setSqlResultList(query.list());

				return null;
			}

		});
		return queryResult;
	}

	// ////////////////////////////////////////////////////////////

	@Override
	public PageResult<T> getScroll(final String preHql, final int firstindex,
			final int maxresult, final String wherejpql,
			final Object[] queryParams,
			final LinkedHashMap<String, String> orderby) {
		final PageResult<T> queryResult = new PageResult<T>();

		super.getHibernateTemplate().execute(new HibernateCallback<T>() {

			public T doInHibernate(Session session) throws HibernateException,
					SQLException {

				String hql = preHql
						+ " from "
						+ entityClassName
						+ " o "
						+ (wherejpql == null || "".equals(wherejpql.trim()) ? ""
								: " where " + wherejpql)
						+ buildOrderby(orderby);

				Query query = session.createQuery(hql);

				setQueryParams(query, queryParams);// where
				queryResult.setTotalRecord(query.list().size());// first get
																// size

				if (firstindex != -1 && maxresult != -1)
					query.setFirstResult(firstindex).setMaxResults(maxresult);// last
																				// page

				queryResult.setResultList(query.list());

				return null;
			}

		});
		return queryResult;
	}
	
}
